package com.baby.movie.widget;

import java.util.Formatter;
import java.util.Locale;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.MediaController.MediaPlayerControl;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.baby.movie.R;

public class MMediaController extends RelativeLayout {

	private static final int FADE_OUT = 1;
	private static final int SHOW_PROGRESS = 2;
	private static final int sDefaultTimeout = 5000;

	private MediaPlayerControl mPlayer;

	private Context mContext;

	private ImageView mVPuase, mVFullScreen;

	private SeekBar mProgress;

	private TextView mTvTime;

	private Formatter mFormatter;

	private StringBuilder mFormatBuilder;

	private OnShowListener mOnShowListener;

	private boolean mShowing;
	private boolean mDragging;

	public MMediaController(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	public MMediaController(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public MMediaController(Context context) {
		super(context);
		init(context);
	}

	private void init(Context context) {
		mContext = context;
		makeControllerView();
	}

	public void setOnShowListenr(OnShowListener listener) {
		mOnShowListener = listener;
	}

	public void setMediaPlayer(MediaPlayerControl player) {
		mPlayer = player;
		updatePausePlay();
	}

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			int pos;
			switch (msg.what) {
			case FADE_OUT:
				hide();
				break;
			case SHOW_PROGRESS:
				pos = setProgress();
				if (!mDragging && mShowing && mPlayer.isPlaying()) {
					msg = obtainMessage(SHOW_PROGRESS);
					sendMessageDelayed(msg, 1000 - (pos % 1000));
				}
				break;
			}
		}
	};

	private void makeControllerView() {
		LayoutInflater.from(mContext).inflate(R.layout.custom_media_controller,
				this, true);
		mVPuase = (ImageView) findViewById(R.id.pause);
		mVPuase.setOnClickListener(mPauseListener);
		mVFullScreen = (ImageView) findViewById(R.id.fullScreen);
		mProgress = (SeekBar) findViewById(R.id.mediacontroller_progress);
		mProgress.setMax(1000);
		mProgress.setOnSeekBarChangeListener(mSeekListener);
		mTvTime = (TextView) findViewById(R.id.time);
		mFormatBuilder = new StringBuilder();
        mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
	}
	
	// There are two scenarios that can trigger the seekbar listener to trigger:
    //
    // The first is the user using the touchpad to adjust the posititon of the
    // seekbar's thumb. In this case onStartTrackingTouch is called followed by
    // a number of onProgressChanged notifications, concluded by onStopTrackingTouch.
    // We're setting the field "mDragging" to true for the duration of the dragging
    // session to avoid jumps in the position in case of ongoing playback.
    //
    // The second scenario involves the user operating the scroll ball, in this
    // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications,
    // we will simply apply the updated position without suspending regular updates.
    private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
        public void onStartTrackingTouch(SeekBar bar) {
            show(3600000);

            mDragging = true;

            // By removing these pending progress messages we make sure
            // that a) we won't update the progress while the user adjusts
            // the seekbar and b) once the user is done dragging the thumb
            // we will post one of these messages to the queue again and
            // this ensures that there will be exactly one message queued up.
            mHandler.removeMessages(SHOW_PROGRESS);
        }

        public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
            if (!fromuser) {
                // We're not interested in programmatically generated changes to
                // the progress bar's position.
                return;
            }

            long duration = mPlayer.getDuration();
            long newposition = (duration * progress) / 1000L;
            mPlayer.seekTo( (int) newposition);
            mTvTime.setText(stringForTime( (int) newposition));
        }

        public void onStopTrackingTouch(SeekBar bar) {
            mDragging = false;
            setProgress();
            updatePausePlay();
            show(sDefaultTimeout);

            // Ensure that progress is properly updated in the future,
            // the call to show() does not guarantee this because it is a
            // no-op if we are already showing.
            mHandler.sendEmptyMessage(SHOW_PROGRESS);
        }
    };

	private View.OnClickListener mPauseListener = new View.OnClickListener() {
		public void onClick(View v) {
			doPauseResume();
			show(sDefaultTimeout);
		}
	};

	public void setFullScreenClickListener(OnClickListener listener) {
		mVFullScreen.setOnClickListener(listener);
	}

	private void doPauseResume() {
		if (mPlayer.isPlaying()) {
			mPlayer.pause();
		} else {
			mPlayer.start();
		}
		updatePausePlay();
	}

	private void updatePausePlay() {
		if (mPlayer.isPlaying()) {
			mVPuase.setImageResource(R.drawable.ic_media_pause);
		} else {
			mVPuase.setImageResource(R.drawable.ic_media_play);
		}
	}

	public boolean isShowing() {
		return mShowing;
	}

	/**
	 * Show the controller on screen. It will go away automatically after 3
	 * seconds of inactivity.
	 */
	public void show() {
		show(sDefaultTimeout);
	}

	/**
	 * Show the controller on screen. It will go away automatically after
	 * 'timeout' milliseconds of inactivity.
	 * 
	 * @param timeout
	 *            The timeout in milliseconds. Use 0 to show the controller
	 *            until hide() is called.
	 */
	public void show(int timeout) {
		setVisibility(VISIBLE);
		setProgress();
		mVPuase.requestFocus();
		mShowing = true;
		updatePausePlay();

		// cause the progress bar to be updated even if mShowing
		// was already true. This happens, for example, if we're
		// paused with the progress bar showing the user hits play.
		mHandler.sendEmptyMessage(SHOW_PROGRESS);

		Message msg = mHandler.obtainMessage(FADE_OUT);
		if (timeout != 0) {
			mHandler.removeMessages(FADE_OUT);
			mHandler.sendMessageDelayed(msg, timeout);
		}
		if (null != mOnShowListener) {
			mOnShowListener.onShow();
		}
	}

	/**
	 * Remove the controller from the screen.
	 */
	public void hide() {
		if (mShowing) {
			setVisibility(GONE);
			mHandler.removeMessages(SHOW_PROGRESS);
			mShowing = false;
			if (null != mOnShowListener) {
				mOnShowListener.onHide();
			}
		}
	}

	private int setProgress() {
		if (mPlayer == null || mDragging) {
			return 0;
		}
		int position = mPlayer.getCurrentPosition();
		int duration = mPlayer.getDuration();
		if (mProgress != null) {
			if (duration > 0) {
				// use long to avoid overflow
				long pos = 1000L * position / duration;
				mProgress.setProgress((int) pos);
			}
			int percent = mPlayer.getBufferPercentage();
			mProgress.setSecondaryProgress(percent * 10);
		}

		String time = stringForTime(position) + "/" + stringForTime(duration);
		mTvTime.setText(time);

		return position;
	}

	private String stringForTime(int timeMs) {
		int totalSeconds = timeMs / 1000;

		int seconds = totalSeconds % 60;
		int minutes = (totalSeconds / 60) % 60;
		int hours = totalSeconds / 3600;

		mFormatBuilder.setLength(0);
		if (hours > 0) {
			return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds)
					.toString();
		} else {
			return mFormatter.format("%02d:%02d", minutes, seconds).toString();
		}
	}

	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		mHandler.removeCallbacksAndMessages(null);
		mHandler = null;
	}

	public interface OnShowListener {

		void onShow();

		void onHide();
	}
}
